#ifndef _DATE_CPP
#define _DATE_CPP

#include "Date.h"
#include <algorithm>
using namespace std;

Date::Date() {
	year_ = -1;
	month_ = -1;
	day_ = -1;
	hour_ = -1;
	minute_ = -1;
}


Date::Date( int year, int month, int day, int hour, int minute ) {
	year_ = year;
	month_ = month;
	day_ = day;
	hour_ = hour;
	minute_ = minute;
}


int Date::getYear( ) const {
	return year_;
}


void Date::setYear( int year ) {
	year_ = year;
}


int Date::getMonth( ) const {
	return month_;
}


void Date::setMonth( int month ) {
	month_ = month;
}


int Date::getDay( ) const {
	return day_;
}


void Date::setDay( int day ) {
	day_ = day;
}


int Date::getHour( ) const {
	return hour_;
}


void Date::setHour( int hour ) {
	hour_ = hour;
}


int Date::getMinute( ) const {
	return minute_;
}


void Date::setMinute( int minute ) {
	minute_ = minute;
}


bool Date::isValid( Date d ) {
	// Static function to check if a date is valid


	// condition 1: 1000 <= year_ <= 9999 ..
	if(d.year_<1000 || d.year_>9999) return false;

	// condition 2: 1 <= month_ <= 12 ..
	if(d.month_<1 || d.month_>12) return false;

	// condition 3: day_ meets the corresponding month_ ..
	if(d.day_<1) return false; // day_ < 1, not valid
	switch(d.month_) {
	case 1:case 3:case 5:case 7:case 8:case 10:case 12: // months with 31 days ..
		if(d.day_>31) return false;
		break;
	case 4:case 6:case 9:case 11: // months with 30 days ..
		if(d.day_>30) return false;
		break;
	case 2: // Feb. ..
		if(d.year_%400==0 || (d.year_%4==0 && d.year_%100!=0)) {
			// leap year_, Feb. with 29 days ..
			if(d.day_>29) return false;
		}
		else {
			// Feb. with 28 days ..
			if(d.day_>28) return false;
		}
	}

	// condition 4: 0 <= hour_ <= 23 .. (no 24, because 24:00 == 0:00)
	if(d.hour_<0 || d.hour_>24) return false;

	// condition 5: 0 <= minute_ <= 59 ..
	if(d.minute_<0 || d.minute_>59) return false;

	// all pass, return true ..
	return true;

}


int strToInt( const string &str ) {
	// function to convert a string into an positive integer ..

	int n = 0;

	if(str.length()==0) return 0;
	if(str.length()==1) return (str[0]-'0');

	int exp = 10; for(int i=2; i<str.length(); ++i) exp *= 10;

	for(int i=0; i<str.length(); ++i) {
		n += (str[i]-'0')*exp;
		exp /= 10;
	}

	return n;
}


bool breakStr(const string &str, const char &ch, string &str1, string &str2) {
	// function to break a string into two substrings by ch ..

	size_t found;


	// find the character ch in the string ..
	found = str.find(ch);

	// if no ch inside, return false indicating failure breaking the string ..
	if(found == string::npos) return false;

	// found, break the string into str1 and str2 ..
	str1 = str.substr(0, found);
	str2 = str.substr(found + 1);

	// all done, return true ..
	return true;
}



Date Date::stringToDate(string ds) {
	// static function to convert a string into Date ..

	Date d; // date with all -1 
	string str1;
	string str2;
	string strtmp;


	// get the year_ .. (yyyy-mm-dd/hh:mm)
	if(!(breakStr(ds,'-',str1,str2))) return d; // wrong expression, return a wrong date ..
	d.year_ = strToInt(str1);
	strtmp = str2;

	// get the month_ .. (mm-dd/hh:mm)
	if(!(breakStr(strtmp,'-',str1,str2))) return d; // wrong expression, return a wrong date ..
	d.month_ = strToInt(str1);
	strtmp = str2;

	// get the day_ .. (dd/hh:mm)
	if(!(breakStr(strtmp,'/',str1,str2))) return d; // wrong expression, return a wrong date ..
	d.day_ = strToInt(str1);
	strtmp = str2;

	// get the hour_ .. (hh:mm)
	if(!(breakStr(strtmp,':',str1,str2))) return d; // wrong expression, return a wrong date ..
	d.hour_ = strToInt(str1);

	// get the minute_ .. (mm)
	if(str2.length()==0) return d; // wrong expression, return a wrong date ..
	d.minute_ = strToInt(str2);

	// return the result ..
	return d;
}


string intToStr(int n) {
	// function to convert an integer into string ..

	int tmp;
	int digit = 0;
	string s = "";


	// get the digit of the number n .. 
	tmp = n;
	for(digit=0;tmp!=0;++digit) tmp /= 10;
	if(n==0) digit=1;

	// convert char by char ..
	for( ; digit>0; --digit) {
		s = s + (char)(n - (int)(n/10)*10 + '0');
		n /= 10;
	}

	// reverse the string ..
	reverse(s.begin(), s.end());

	// return the result ..
	return s;
}


string Date::dateToString(Date d) {
	// static function to convert a date to string ..

	string ds = "";


	// process the minute_ format ..
	string smu = intToStr(d.minute_);
	if(smu.length()==1) smu = "0" + smu;

	// convert the date into string .. 
	ds = intToStr(d.year_) + "-" + intToStr(d.month_) + "-" + intToStr(d.day_) + "/" + intToStr(d.hour_) + ":" + smu;

	// return the result ..
	return ds;
}


Date& Date::operator=( const Date& t ) {
	this->year_ = t.year_;
	this->month_ = t.month_;
	this->day_ = t.day_;
	this->hour_ = t.hour_;
	this->minute_ = t.minute_;

	return (*this);
}


bool Date::operator==( const Date& t ) const {

	// if all equal, return true ..
	if(this->year_==t.year_ && this->month_==t.month_ && this->day_==t.day_ && this->hour_==t.hour_ && this->minute_==t.minute_) 
		return true;

	// otherwise, return false ..
	return false;
}


bool Date::operator>( const Date& t) const {

	// compare year_ ..
	if(this->year_!=t.year_) return (this->year_>t.year_);

	// compare month_ ..
	if(this->month_!=t.month_) return (this->month_>t.month_);

	// compare day_ ..
	if(this->day_!=t.day_) return (this->day_>t.day_);

	// compare hour_ ..
	if(this->hour_!=t.hour_) return (this->hour_>t.hour_);

	// compare minute_ ..
	if(this->minute_!=t.minute_) return (this->minute_>t.minute_);

	// all equal ..
	return false;
}


bool Date::operator<( const Date& t ) const {

	// <  is  !(== || >) ..
	return !((*this)==t || (*this)>t);
}


bool Date::operator>=( const Date& t) const {

	// >=  is  (> || ==) ..
	return ((*this)>t || (*this)==t);
}


bool Date::operator<=( const Date& t ) const {

	// <=  is  (< || ==) ..
	return ((*this)<t || (*this)==t);
}


#endif

